﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Gezel.Model;

#endregion

namespace Weazel.Gezel.Conversions.Model
{
  /// <summary>
  /// The SignalFlowGraphSet represents a collection 
  /// of signal flow graphs which will be executed in
  /// parallel for a given control step.
  /// </summary>
  public class ExecutionSet : List<SignalFlowGraph>
  {
    /// <summary>
    /// Control step during which
    /// this set of sfg is activated
    /// </summary>
    private readonly int controlStepId;
    public int ControlStepId
    {
      get { return controlStepId; }
    }

    private readonly List<SignalType> signalDependencies;
    public List<SignalType> SignalDependencies
    {
      get { return signalDependencies; }
    }

    private readonly List<OutPortType> outportDependencies;
    public List<OutPortType> OutportDependencies
    {
      get { return outportDependencies; }
    }

    private readonly List<RegisterType> registerDependencies;
    public List<RegisterType> RegisterDependencies
    {
      get { return registerDependencies; }
    }

    private SoftwareModel softwareModel;

    /// <summary>
    /// Creates a new sfg execution set for the
    /// specified control step
    /// </summary>
    /// <param name="controlStep"></param>
    public ExecutionSet(SoftwareModel softwareModel, int controlStep) 
    {
      this.softwareModel = softwareModel;
      this.controlStepId = controlStep;
      this.signalDependencies = new List<SignalType>();
      this.registerDependencies = new List<RegisterType>();
      this.outportDependencies = new List<OutPortType>();
    }

    /// <summary>
    /// Creates a new sfg execution set for the
    /// specified control step and adds
    /// the specified signal flow graph
    /// </summary>
    /// <param name="controlStep"></param>
    /// <param name="sfg"></param>
    public ExecutionSet(SoftwareModel softwareModel, int controlStep, SignalFlowGraph sfg) : this(softwareModel, controlStep)
    {
      Add(sfg);
    }

    public void AnalyzeDependencies()
    {
      foreach (SignalFlowGraph sfg in this)
      {
        List<LeafExpression> leaves = new List<LeafExpression>();
        foreach (Expression expr in sfg.Expressions)
        {
          expr.GetDependentLeafExpressions(ref leaves);
        }

        foreach (LeafExpression leaf in leaves)
        {
          if (leaf.ReferencedEntity is Signal)
          {
            SignalType signalType = softwareModel.GetTypeForSignal(leaf.ReferencedEntity as Signal);
            if (!signalDependencies.Contains(signalType))
              signalDependencies.Add(signalType);
          }
          else if (leaf.ReferencedEntity is OutPort)
          {
            OutPortType outportType = softwareModel.GetTypeForOutport(leaf.ReferencedEntity as OutPort);
            if (!outportDependencies.Contains(outportType))
              outportDependencies.Add(outportType);
          }
          else if (leaf.ReferencedEntity is Register)
          {
            RegisterType registerType = softwareModel.GetTypeForRegister(leaf.ReferencedEntity as Register);
            if (!registerDependencies.Contains(registerType))
              registerDependencies.Add(registerType);
          }
          else if (leaf.ReferencedEntity is InPort)
          {
            InPort inport = leaf.ReferencedEntity as InPort;

            if (softwareModel.PortMappings.ContainsInport(inport))
            {
              OutPort outPort = softwareModel.PortMappings[leaf.ReferencedEntity as InPort];
              OutPortType outportType = softwareModel.GetTypeForOutport(outPort);
              if (!outportDependencies.Contains(outportType))
                outportDependencies.Add(outportType);
            }
            else
            {
              System.Diagnostics.Trace.Assert(softwareModel.SignalMappings.ContainsInport(inport));

              Signal signal = softwareModel.SignalMappings[leaf.ReferencedEntity as InPort];
              SignalType signalType = softwareModel.GetTypeForSignal(signal);
              if (!signalDependencies.Contains(signalType))
                signalDependencies.Add(signalType);
            }
          }
        }
      }
    }

    public override string ToString()
    {
      StringBuilder builder = new StringBuilder();
      
      builder.AppendFormat("control step {0} (", controlStepId);

      foreach (SignalFlowGraph sfg in this)
      {
        builder.AppendFormat("{0},", sfg.LocalName);
      }
      
      builder.Remove(builder.Length - 1, 1);

      builder.Append(")\n\tregister dependencies: ");

      foreach (RegisterType reg in registerDependencies)
      {
        builder.AppendFormat("{0},", reg.Name);
      }

      builder.Remove(builder.Length - 1, 1);
      builder.Append("\n\toutport dependencies: ");

      foreach (OutPortType reg in outportDependencies)
      {
        builder.AppendFormat("{0},", reg.Name);
      }

      builder.Remove(builder.Length - 1, 1);
      builder.Append("\n\tsignal dependencies: ");

      foreach (SignalType reg in signalDependencies)
      {
        builder.AppendFormat("{0},", reg.Name);
      }

      builder.Remove(builder.Length - 1, 1);
      builder.AppendLine("");
      

      return builder.ToString();
    }
  }
}
